home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
src
/
derror
/
bug2.c
next >
Wrap
C/C++ Source or Header
|
1997-09-09
|
20KB
|
751 lines
/*
* (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
* use is allowed under the terms of the DICE-LICENSE FILE,
* DICE-LICENSE.TXT.
*/
#include <stdio.h>
#include <exec/types.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <string.h>
#include <stdlib.h>
#include <clib/exec_protos.h>
#include <lib/rexx.h>
#include "error_rev.h"
#define PORTNAME "DICE_ERROR_PARSER"
typedef struct ErrorInfo {
struct ErrorInfo *next;
struct ErrorInfo *prev;
char line[1];
} EInfo;
struct FileInfo {
struct FileInfo *next;
struct FileInfo *prev;
char *dir;
char *args;
struct ErrorInfo base;
struct ErrorInfo *cur;
};
struct FileInfo files;
struct FileInfo *curfile;
char *RexxHostName = NULL; /* no automatic start */
#define MAX_FILENAME 1024
char buf[MAX_FILENAME+1];
short active;
/***********************************************************************************
* Procedure: AddLine
* Synopsis: AddLine(FileInfo *, char *)
* Purpose: Adds the line to the current file information. If there is not enough
* memory, it will simply ignore the line silently.
***********************************************************************************/
void AddLine(struct FileInfo *fi, char *line)
{
struct ErrorInfo *ei;
ei = malloc(sizeof(struct ErrorInfo) + strlen(line));
if (ei)
{
ei->prev = fi->base.prev;
ei->next = fi->base.prev->next;
fi->base.prev->next = ei;
fi->base.prev = ei;
}
}
/***********************************************************************************
* Procedure: NewFI
* Synopsis: FileInfo = NewFI(char *dir, char *args)
* Purpose: Creates a new file info. If it is unable to, it returns NULL
***********************************************************************************/
struct FileInfo *NewFI(char *dir, char *args)
{
struct FileInfo *fi;
fi = malloc(sizeof(struct FileInfo));
if (fi)
{
fi->dir = strdup(dir);
if (fi->dir)
{
fi->args = strdup(args);
if (fi->args)
{
fi->prev = files.prev;
fi->next = files.prev->next;
files.prev->next = fi;
files.prev = fi;
fi->base.prev = fi->base.next = &fi->base;
fi->cur = NULL;
}
else
{
free(fi->dir);
free(fi);
fi = NULL;
}
}
else
{
free(fi);
fi = NULL;
}
}
return(fi);
}
/***********************************************************************************
* Procedure: FreeFI
* Synopsis: FreeFI(struct FileInfo *)
* Purpose: Removes a FileInfo structure from the list
***********************************************************************************/
void FreeFI(struct FileInfo *fi)
{
struct ErrorInfo *ei;
/* Handle any attempts to free the base FI */
if (fi == files) return;
/* Unlink us from the chain of file handles */
fi->prev->next = fi->next;
fi->next->prev = fi->prev;
/* Update any system pointers which might look at what we are going to free */
if (curfile == fi)
{
curfile = files.next;
if (curfile == files) curfile = NULL; // no more anyway
}
/* Free all the lines */
fi->base.prev->next == NULL; // mark our stopping point
for(ei = fi->base.next; ei != NULL;)
{
struct ErrorInfo *sei;
sei = ei;
ei = ei->next;
free(sei);
}
/* Finally, get rid of the file information */
free(fi->dir);
free(fi->args);
free(fi);
}
k
/***********************************************************************************
* Procedure: say
* Synopsis: (void)say(msg);
* Purpose: Displays the given message on the console
***********************************************************************************/
void say(char *msg)
{
BPTR out;
out = Output();
if (out)
{
Write(out, msg, strlen(msg));
Write(out, "\n", 1);
}
}
/***********************************************************************************
* Procedure: usage
* Synopsis: (void)usage();
* Purpose: Displays the command line usage message - does not return
***********************************************************************************/
void usage(void)
{
say("FILE/M,MACRO/K,PROJECT/K" VERSTAG);
exit(20);
}
/***********************************************************************************
* Procedure: mustmalloc
* Synopsis: mem = mustmalloc(size);
* Purpose: Allocates memory or Displays an outof memory message -
* if there is not enough memory, it does not return
***********************************************************************************/
void *mustmalloc(int size)
{
void *r;
r = malloc(size);
if (r == NULL)
{
say("No Memory!\n");
exit(20);
}
return(r);
}
/***********************************************************************************
* Procedure: dottx
* Synopsis: result = dottx(port, cmd);
* Purpose: Sends a command to TurboText
***********************************************************************************/
char *dottx(char *port, char *cmd)
{
char *res;
long ec;
if (port == NULL) port = "TURBOTEXT";
PlaceRexxCommandDirect(NULL, port, cmd, &res, &ec);
return(res);
}
/***********************************************************************************
* Procedure: full_path
* Synopsis: path = full_path(name)
* Purpose: Constructs a fully expanded filename
* Note, we can not assume that the file exists, so it will not be possible
* to actually lock it. We can assume that the directory it is part of
* does exist.
***********************************************************************************/
char *full_path(char *name)
{
BPTR lock;
__aligned struct FileInfoBlock fib;
char *tail, *p;
int pos;
/* Step 1 - split out any directory information from the actual name */
p = strrchr(name, '/');
if (p == NULL) p = strrchr(name, ':');
if (p != NULL)
{
/* There was some directory information involved */
char c;
tail = strdup(p+1);
c = p[1];
p[1] = 0;
lock = Lock(name, SHARED_LOCK);
p[1] = c;
}
else
{
/* No directory information involved, just the name relative to the */
/* current directory */
lock = Lock("", SHARED_LOCK);
tail = strdup(name);
}
/* Step 2 - we have the lock on the directory and the tail part of the name */
/* We want to construct a fully qualified path for the directory. */
/* If for some reason the lock on the directory returned 0, we want to just */
/* return the name they gave us to begin with. */
if (lock == 0)
{
free(tail);
return(strdup(name));
}
/* Step 3 - Fully qualify the directory portion into the buffer */
if (DOSBase->dl_lib.lib_Version >= 36)
{
if (!NameFromLock(lock, buf, MAX_FILENAME))
{
/* Either the name is too long or there was something else wrong with */
/* the file name, just return what they gave us as a start */
UnLock(lock);
free(tail);
return(strdup(name));
}
UnLock(lock);
pos = 0;
}
else
{
/* Running under 1.3, we have to do this the old fashion way */
/* Just so we don't have to do any inserts/extra copies, we will work */
/* from the end of the buffer and insert as we go */
pos = MAX_FILENAME;
buf[--pos] = 0;
while(lock != 0)
{
BPTR parent;
int len;
/* Examine the lock to get the name for it */
Examine(lock, &fib);
/* Find the parent of this directory */
parent = ParentDir(lock);
UnLock(lock);
lock = parent;
len = strlen(fib.fib_FileName);
pos -= 1;
if (len > pos)
{
/* oops, not enough room, just return the name they gave us */
UnLock(lock);
free(tail);
return(strdup(name));
}
buf[pos] = lock ? ':' : '/';
pos -= len;
memcpy(buf+pos, fib.fib_FileName, len);
}
}
/* We have the path part in the buffer and the name part in the tail */
/* All that is left is to concatenate them together correctly */
{
int len;
/* Successful, the buf holds the path for the directory. We will need */
/* to add a / to the end if it doesn't end in a colon */
len = strlen(buf+pos);
if ((buf[pos+len-1] != ':') && (buf[pos+len-1] != '/'))
{
buf[pos+len++] = '/';
buf[pos+len] = 0;
}
name = malloc(len+strlen(tail)+1);
if (name != NULL)
{
strcpy(name, buf+pos);
strcpy(name+len, tail);
}
}
return(name);
}
/*
* This sets the appropriate AREXX stem variables for the return
* FILE: The name of the file to edit
* DIR: The directory that the file is relative to
* LINE: The line number of the file to go to
* COL: The column number in the file
* ERRNO: The error number
* STRING: The error message to be printed out
*/
void SetStem(void *rxmsg, char *stem, EInfo *einfo)
{
char stembuf[40];
int len;
char *p;
/* DC1: "fails.c" L:1 C:1 W:68 expected semicolon */
strncat(stembuf, stem, 32);
stembuf[32] = 0;
len = strlen(stembuf);
p = stembuf+len;
strcpy(p, ".FILE");
SetRexxVar(rxmsg, stembuf, "FILENAME", 8);
strcpy(p, ".DIR");
SetRexxVar(rxmsg, stembuf, "DIRECTORY/DIR", 13);
strcpy(p, ".LINE");
SetRexxVar(rxmsg, stembuf, "12", 2);
strcpy(p, ".COL");
SetRexxVar(rxmsg, stembuf, "4", 1);
strcpy(p, ".ERRNO");
SetRexxVar(rxmsg, stembuf, "42", 2);
strcpy(p, ".STRING");
SetRexxVar(rxmsg, stembuf, "Complete Error Message", 22);
}
/*
* We handle the following Rexx Commands:
* Quit
* Next <stem>
* First <stem>
* Prev <stem>
* Clear
* TTXSame <file>
* Load <error> <dir> <sourcefile> <R0> <R1> <R2> <R3> <R4> <R5> <R6> <R7> <R8> <R9>
*
* Where <stem> Is any valid rexx variable name
*/
long
DoRexxCommand(msg, port, arg0, pres)
void *msg; /* RexxMsg structure if we need it */
struct MsgPort *port; /* MsgPort structure if we need it */
char *arg0; /* arg0 */
char **pres; /* where to put our result if rc==0 */
{
int rc;
char cmd[9];
int i;
char *p, *t;
printf("MatchCheck %s vs %s\n", arg0, "pass");
strncpy(cmd, arg0, 8);
cmd[8] = 0; // Ensure that the string is properly terminated
p = strchr(cmd, ' ');
if (p) *p = 0;
p = arg0+strlen(cmd);
while (*p == ' ') p++;
if (!stricmp(cmd, "QUIT"))
{
active = 0;
rc = 0;
}
else if (!stricmp(cmd, "NEXT"))
{
SetStem(msg, p, NULL);
*pres = "NEXT Command Complete";
rc = 0;
}
else if (!stricmp(cmd, "FIRST"))
{
SetStem(msg, p, NULL);
*pres = "FIRST Command Complete";
rc = 0;
}
else if (!stricmp(cmd, "PREV"))
{
SetStem(msg, p, NULL);
*pres = "PREV Command Complete";
rc = 0;
}
else if (!stricmp(cmd, "CLEAR"))
{
*pres = "All Errors Cleared";
rc = 0;
}
else if (!stricmp(cmd, "TTXSAME"))
{
*pres = "TTXSAME not activated";
rc = 0;
}
else if (!stricmp(cmd, "LOAD"))
{
SetStem(msg, "BASE", NULL);
*pres = "success!";
rc = 0;
}
else
{
*pres = "Command Unknown";
rc = 5;
}
return(rc);
}
#if 0
Pass : DC1, DAS, DCPP, DLINK
File : Char *
Dir :
Line : Short
Column: Short
Type : W, E, F
Number: Char
String: Char *
DC1: "fails.c" L:1 C:1 W:68 expected semicolon
DC1: "fails.c" L:2 C:1 W:68 expected semicolon
DC1: "fails.c" L:4 C:1 W:68 expected semicolon
DC1: "fails.c" L:6 C:1 W:68 expected semicolon
DC1: "fails.c" L:7 C:10 W:68 expected semicolon
DC1: "fails.c" L:7 C:1 W:68 expected semicolon
DC1: "fails.c" L:8 C:1 W:68 expected semicolon
DC1: "fails.c" L:10 C:1 W:68 expected semicolon
SetRexxVar(pending->rxmsg,stem,file_name, strlen(file_name));
Configuration Options:
Edit Command
#
# Quick-Fix Error Handling. Pops up your editor pointing to any
# warnings or errors. Enable with the -R option to DCC.
#
# port= never_happen ;Run REXX script
# port= REXX ;Talk directly to REXX
# port= your application ;Talk directly to "your application"
cmd=
port=
rexxcmd=
linkcmd=
linkport=
linkrexxcmd=
#
#
# %e Error temporary file name
# %f Fully qualified source file name
# %d Directory containing the source
# %n Filepart of source
# %c Current Directory (where DCC was run from)
# %0-%9 argument from -R0/-R9 DCC option (e.g. -R0 fubar)
#
# Note: A space is not allowed between the keyword and the =!
#
#cmd= TTX %e MACRO "DCC:Rexx/ParseError.ttx %f %c %0"
port= DICE_ERROR_PARSER
cmd= Load %e %d %f %0 %1 %2 %3 %4 %5 %6 %7 %8 %9
#include "TTXSame_Rev.h"
extern struct Library *RexxSysBase;
extern struct DosLibrary *DOSBase;
struct SAVER {
struct SAVER *next;
char *fname;
};
char *RexxHostName = NULL;
/***********************************************************************************
* Procedure: main
* Synopsis: rc = main(argc, argv);
* Purpose: Main entry point
***********************************************************************************/
int ttxmain(int argc, char **argv)
{
char *res;
int i;
char *macro;
char *project;
struct SAVER base, *nsaver;
project = NULL;
macro = NULL;
if (RexxSysBase == NULL)
{
say("Unable to open rexxsyslib.library!");
exit(20);
}
CreateDiceRexxPort(NULL, NULL);
nsaver = &base;
base.next = NULL;
if ((argc == 2) && (!strcmp(argv[1], "?"))) usage();
/* Template for command: */
/* FILE/M,MACRO/S,PROJECT/S */
for (i = 1; i < argc; i++)
{
if (!stricmp(argv[i], "MACRO"))
{
if (++i >= argc) usage();
if (macro != NULL) usage();
macro = mustmalloc(strlen(argv[i]) + 16); /* ExecArexxMacro */
strcpy(macro, "ExecArexxMacro ");
strcat(macro, argv[i]);
}
else if (!stricmp(argv[i], "PROJECT"))
{
if (++i >= argc) usage();
project = argv[i];
}
else
{
if (!stricmp(argv[i], "FILE"))
{
if (++i >= argc) usage();
}
nsaver->next = mustmalloc(sizeof(struct SAVER));
nsaver = nsaver->next;
nsaver->fname = full_path(argv[i]);
nsaver->next = NULL;
}
}
/* We have parsed our parameters, now we need to load each of the files */
/* specified into the editor. In the process we will have to check for */
/* Any files in the editor to ensure that they are not already loaded */
while((nsaver = base.next) != NULL)
{
/* Send the command off to rexx to be processed */
/* We will wait here until it is complete */
res = dottx(NULL, "GETDOCUMENTS");
if (res != NULL)
{
char *p, *t, *fname, *pname;
int len;
/* Now we need to go through and figure out all the files that are there */
fname = res;
pname = NULL;
while(*fname)
{
if (*fname != '"')
{
say("TURBOTEXT Sync Error");
return(20);
}
fname++;
t = fname;
len = strlen(t);
while ((len > 11) && memcmp(t, "\" TURBOTEXT", 11)) /* Bug with no parm */
{
char *s;
s = strchr(t+1, '"');
if (s == NULL) break;
len -= (s-t);
t = s;
}
/* At this point, t should be pointing at the " in the name */
*t = 0;
/* Now we want to get the portname for the file */
t += 2;
pname = t;
while(*t && (*t != ' ')) t++;
if (*t) *t++ = 0;
p = dottx(pname, "GetFilePath");
/* If this is the file that we are interested in, drop out of the */
/* loop and go to work on it in the file */
if ((p != NULL) && !stricmp(nsaver->fname, p))
break;
/* Advance to let the next stuff work */
fname = t;
while(*fname == ' ') fname++;
pname = NULL;
}
/* If we got a match, the port will tell us who to talk to */
if (pname == NULL)
{
char *ocmd;
ocmd = mustmalloc(strlen(nsaver->fname) + 15); /* OPENDOC NAME */
strcpy(ocmd, "OPENDOC NAME ");
strcat(ocmd, nsaver->fname);
pname = dottx(NULL, ocmd);
free(ocmd);
}
else
{
char *p;
p = dottx(pname, "WINDOW2FRONT");
if (p != NULL) free(p);
p = dottx(pname, "SCREEN2FRONT");
if (p != NULL) free(p);
}
{
char *p;
p = dottx(pname, "ACTIVATEWINDOW");
if (p != NULL) free(p);
}
/* We now have the document open, pname is the port to talk to */
if (project != NULL)
{
char *ocmd;
/* ExecARexxString call setclip(TTX_TURBOTEXT12,myport.1) */
/* 123456789012345678901234567890123 4 5 */
ocmd = mustmalloc(strlen(project)+strlen(pname)+36);
strcpy(ocmd, "ExecARexxString call setclip(TTX_");
strcat(ocmd, pname);
strcat(ocmd, ",");
strcat(ocmd, project);
strcat(ocmd, ")");
p = dottx(pname, ocmd);
if (p != NULL) free(p);
free(ocmd);
}
/* Next we want to issue the macro command to make it run */
if (macro != NULL)
{
char *p;
p = dottx(pname, macro);
if (p != NULL) free(p);
}
free(res);
}
/* Take the entry off the list because we have already processed it */
base.next = nsaver->next;
free(nsaver->fname);
free(nsaver);
}
return(0);
}
#endif
/***********************************************************************************
* Procedure: main
* Synopsis: rc = main(argc, argv);
* Purpose: Main entry point
***********************************************************************************/
int main(ac, av)
char *av[];
{
/*
* DICE automatically opens rexxsyslib.library for us as long
* as we reference the base variable (via extern) and not
* declare it. lib/rexx.h does this for us.
*
* However, unlike other autoinits, if DICE is unable to open
* the library it does not abort the program, hence the following.
*/
if (RexxSysBase == NULL)
{
say("Unable to open rexxsyslib.library !");
exit(20);
}
short r = CreateGlobalDiceRexxPort(NULL, PORTNAME);
if (r < 0)
{
say("AREXX Port " PORTNAME " exists. DError is already running\n");
exit(20);
}
say("Creating port " PORTNAME);
active = 1;
/*
* Our main loop executes received commands
*/
while (active)
{
long mask = Wait(SIGBREAKF_CTRL_C | (1 << RexxSigBit));
if (mask & SIGBREAKF_CTRL_C)
break;
if (mask & (1 << RexxSigBit))
ProcessRexxCommands(NULL);
}
say("DError terminating\n");
return(0);
}